<?php

// uses
class Agilet
{
	/**
	 * container
	 * @var registry
	 */
	static protected $_registry = array();

	/**
	 * protected app base url
	 * @var string
	 */
	static protected $_appUrl = '/';

	/**
	 * static base url liked to our media server
	 * @var string
	 */
	static protected $_staticUrl = 'http://www.k1.vn/static';

	/**
	 * static base url liked to our media server
	 * @var string
	 */
	static protected $_mediaUrl = '/';

	/**
	 * @var Template
	 */
	static protected $_template = null;

	/**
	 * @var int
	 */
	static protected $_appId = 1;

	/**
	 * @var string
	 */
	static protected $_appDomain = 'www.k1.vn';

	/**
	 * get current viewer of none.
	 */
	static protected $_viewer = null;

	/**
	 * get static base url
	 * @return string
	 */
	static public function getStaticUrl()
	{
		return self::$_staticUrl;
	}

	/**
	 * set static base url
	 * @param string $staticUrl
	 * @return void
	 */
	static public function setStaticUrl($staticUrl)
	{
		self::$_staticUrl = $staticUrl;
	}

	/**
	 * @return string
	 */
	static public function getAppUrl()
	{
		return self::$_appUrl;
	}

	/**
	 * @param  string  $baseUrl
	 * @return void
	 */
	static public function setAppUrl($appUrl)
	{
		self::$_appUrl = $appUrl;
	}

	/**
	 * @return string
	 */
	static public function getMediaUrl()
	{
		return self::$_mediaUrl;
	}

	/**
	 * @param  string  $baseUrl
	 * @return void
	 */
	static public function seMediaUrl($mediaUrl)
	{
		self::$_mediaUrl = $mediaUrl;
	}

	/**
	 * rerieves a variable regiester to registry
	 */
	static public function getRegistry($key, $default = null)
	{
		return isset(self::$_registry[$key]) ? self::$_registry[$key] : $default;
	}

	static public function setRegistry($key, $value)
	{
		self::$_registry[$key] = $value;
	}

	/**
	 * load configuration file
	 * it seems always return array
	 * @return array
	 */
	static public function loadConfig($file, $offset = null, $dir = null)
	{
		if (null == $dir)
		{
			$dir = AGILET_SETTING_PATH;
		}

		$filename = $dir . '/' . $file;

		if (!file_exists($filename))
		{
			throw new Exception("Invalid configuration file under config directory $filename");
		}

		$data =
		include $filename;

		if ($offset)
		{
			if (!isset($data[$offset]))
			{

				throw new Exception("invalid configuration offset $file:$offset");
			}
			return $data[$offset];
		}
		return $data;
	}

	static public function hasClass($class_name)
	{
		return class_exists($class_name) or self::__autoload($class_name);
	}

	/**
	 * find class
	 * @param string $class_name
	 * @return true/false
	 */
	static public function requireClass($path, $module = 'system')
	{
		return class_exists($class_name) or self::__autoload($class_name);
	}

	/**
	 * factory a resource object
	 *
	 * @param      string     $name
	 * @param      string     $ext
	 * @return     Object
	 */
	static public function __resource($name, $ext = null)
	{
		if (self::hasClass($class_name = self::sanitizeClass($name)))
		{
			return new $class_name;
		}

		throw new Exception("class $name $ext does not exists!");
	}

	/**
	 * @param     string $name
	 * @param     string $ext
	 * @return    string class name
	 */
	static public function sanitizeClass($name, $ext)
	{
		if ($ext)
		{
			$name = trim(str_replace('@', '.' . $ext . '.', $name), '.');
		}
		return implode('_', array_map('ucfirst', explode('.', $name)));
	}

	static public function __autoload($class_name)
	{
		$paths = array(
			AGILET_LIBRARY_PATH,
			AGILET_APPLICATION_PATH
		);

		$filename = str_replace('_', '/', strtolower($class_name)) . '.php';
		foreach ($paths as $path)
		{
			if (file_exists($file = $path . '/' . $filename))
			{
				require_once $file;
				return TRUE;
			}
		}

		return FALSE;

	}

	static public function getBacktrace()
	{
		$backtrace = array_slice(debug_backtrace(), 1);
		$output = '';
		$output .= 'Stack trace:' . PHP_EOL;

		foreach ($backtrace as $index => $stack)
		{
			// Process args
			$args = array();
			if (!empty($stack['args']))
			{
				foreach ($stack['args'] as $argIndex => $argValue)
				{
					if (is_object($argValue))
					{
						$args[$argIndex] = get_class($argValue);
					}
					else
					if (is_array($argValue))
					{
						$args[$argIndex] = 'Array';
						//substr(print_r($argValue, true), 0, 32);
					}
					else
					if (is_string($argValue))
					{
						$args[$argIndex] = "'" . substr($argValue, 0, 32) . (strlen($argValue) > 32 ? '...' : '') . "'";
					}
					else
					{
						$args[$argIndex] = print_r($argValue, true);
					}
				}
			}
			// Process message
			$output .= sprintf('#%1$d %2$s(%3$d): %4$s%5$s%6$s(%7$s)', $index, (!empty($stack['file']) ? $stack['file'] : '(unknown file)'), (!empty($stack['line']) ? $stack['line'] : '(unknown line)'), (!empty($stack['class']) ? $stack['class'] : ''), (!empty($stack['type']) ? $stack['type'] : ''), $stack['function'], join(', ', $args)) . PHP_EOL;
		}

		// Throw main in there for the hell of it
		$output .= sprintf('#%1$d {main}', $index + 1);

		return str_replace(AGILET_ROOT_PATH, '', $output);
	}

	/**
	 * handle error
	 * @param  int     $errorno
	 * @param  string  $errstr
	 * @param  string  $errfile
	 * @param  int     $errline
	 * @param  handle  $errcontext
	 */
	static public function errorHandler($errno, $errstr, $errfile = null, $errline = null, array $errcontext = null)
	{
		Logger::inst() -> write(Logger::ERROR, sprintf('[%1$d] %2$s (%3$s) [%4$d]' . PHP_EOL . '%5$s', $errno, $errstr, $errfile, $errline, self::getBacktrace()));
		$level = Logger::INFO;
		$fatal = FALSE;

		switch ($errno) {
			case E_USER_NOTICE :
			case E_NOTICE :
				$level = Logger::NOTICE;
				break;
			default :
			case E_USER_WARNING :
			case E_WARNING :
			case E_COMPILE_WARNING :
			case E_CORE_WARNING :
			case E_DEPRECATED :
			case E_STRICT :
			case E_USER_DEPRECATED :
				$level = Logger::WARNING;
				break;
			case E_COMPILE_ERROR :
			case E_CORE_ERROR :
			case E_ERROR :
			case E_PARSE :
			case E_RECOVERABLE_ERROR :
			case E_USER_ERROR :
				$level = Logger::ERR;
				$fatal = TRUE;
				break;
		}

		if ($fatal)
		{
			self::sendFatalError();
		}
		return 1;
	}

	static public function sendFatalError()
	{
		// Clean any previous output from buffer
		while (ob_get_level() > 0)
		{
			ob_end_clean();
		}

		ob_end_clean();
		echo View::render(array(), 'error/fatal.tpl');
		die(1);
	}

	/**
	 * handle exception
	 * @param Exception $exception
	 * @return true/false
	 */
	static public function exceptionHandler($exception)
	{
		Logger::inst() -> write(Logger::ERROR, self::getBacktrace() . PHP_EOL . $exception -> getMessage());
		return 0;
	}

	/**
	 * handle shutdown
	 */
	static public function shutdownHandler()
	{

		/**
		 * code here
		 */
		Logger::inst() -> flush();
	}

	static public function execute()
	{
		$request = Request::initiator();

		try
		{
			$request -> execute();
		}
		catch(Exception $e)
		{
			$request -> execute('error/404');
		}

		// process with layout container.
		$format = $request -> getParam('format');
		$is_ajax = $request -> isAjax();

		switch($format) {
			case 'json' :
			case 'jsonp' :
				return json_encode(array(
					'html' => $request -> response,
					'error' => 0,
					'message' => ''
				));
				break;
			case 'html' :
			case 'xhtml' :
			case 'xml' :
				return $request -> response;
				break;
			case null :
			default :
				return self::getTemplate() -> execute();
		}
	}

	static public function emit($event)
	{

	}

	static public function getUrl($path, $params = null)
	{

		$url = 'http://' . self::$_appDomain . self::$_appUrl . trim($path, '/');

		if ($params)
		{
			$url .= '?' . http_build_query($params, null, '&');
		}
		return $url;
	}

	static function getTemplate()
	{
		if (null == self::$_template)
		{
			self::$_template = new Template;
		}
		return self::$_template;
	}

	/**
	 * get current application id
	 * @return int
	 */
	static public function getAppId()
	{
		return self::$_appId;
	}

	/**
	 * set current app Id
	 * @param int $appId
	 * @return void
	 */
	static public function setAppId($appId)
	{
		self::$_appId = (int)$appId;
	}

	static public function getViewer()
	{
		if (null == self::$_viewer)
		{
			if (isset($_SESSION['uid']) && $id = intval($_SESSION['uid']))
			{
				$user = Mongo_Document::factory('user', $id);
			}
			if (null == $user)
			{
				$user = false;
			}
			self::$_viewer = $user;
		}
		return self::$_viewer;
	}

	/**
	 * get general setting as we need.
	 * @param string $name
	 * @return fixed/array
	 */
	static public function getSetting($name)
	{
		$db = Mongo_Database::instance() -> selectCollection('site_settings');
		$result = $db -> findOne(array('_id' => $name));
		if ($result && isset($result['sval']))
		{
			return $result['sval'];
		}
		return $result;
	}

	/**
	 * @param string $name
	 * @param array $value
	 */
	static public function setSetting($name, $value)
	{
		$db = Mongo_Database::instance() -> selectCollection('site_settings');
		if (is_string($value))
		{
			$value = array('sval' => $value);
		}
		$value['_id'] = $name;
		return $db -> save($value);
	}

	static public function redirect($path, $params = null, $host = null)
	{
		$url = self::getUrl($path, $params, $host);
		header('location:' . $url);
		exit ;
	}

}
